# -*- coding: utf-8 -*-
"""
__mktime__ = '2019/4/15'
__author__ = 'Just'
__filename__ = 'token_auth'
"""
from collections import namedtuple
from flask import current_app, g, request
from flask_httpauth import HTTPBasicAuth
from itsdangerous import TimedJSONWebSignatureSerializer, BadSignature, SignatureExpired
from app.libs.error_code import AuthFailedException, ForbiddenException, ParameterException, NotFoundException
from app.libs.scope import is_in_scope
from app.model.user import User as UserModel

auth = HTTPBasicAuth()
"""认证后的用户信息"""
User = namedtuple('User', ['uid', 'ac_type', 'scope'])


@auth.verify_password
def verify_password(account, password):
    """请求拦截器 校验访问权限"""
    user_info = __verify_auth_token(account)
    if not user_info:
        return False
    else:
        g.user = user_info  # g 线程隔离
        return True


def generate_auth_token(uid, ac_type, scope=None, expiration=7200):
    """
    令牌生成器
    :param uid: 用户id
    :param ac_type: 用户类型
    :param scope: 权限
    :param expiration: 令牌过期时间
    :return: 加密token
    """
    s = TimedJSONWebSignatureSerializer(current_app.config['SECRET_KEY'],
                                        expires_in=expiration)
    return s.dumps({
        'uid': uid,
        'type': ac_type.value,
        'scope': scope
    })


def __verify_auth_token(token):
    """
    验证token
    1.验证token的合法性
    2.解析令牌信息
    3.判断当前接口权限
    :param token:
    :return:
    """
    if token is None or token == '':
        raise ParameterException(msg='没有携带令牌', error_code=8000)
    s = TimedJSONWebSignatureSerializer(current_app.config['SECRET_KEY'])
    try:
        res = s.loads(token)
    except BadSignature:
        raise AuthFailedException(msg='非法令牌', error_code=8002)
    except SignatureExpired:
        raise AuthFailedException(msg='令牌已过期', error_code=8003)
    # 解析令牌信息
    uid = res['uid']
    ac_type = res['type']
    scope = res['scope']
    # 判断当前接口权限
    allow = is_in_scope(scope, request.endpoint)
    if not allow:
        raise ForbiddenException()
    return User(uid, ac_type, scope)


def verify_auth_token_info(token):
    """
    验证token
    1.验证token的合法性
    2.解析令牌信息
    """
    if token is None or token == '':
        raise ParameterException(msg='没有携带令牌', error_code=8000)
    s = TimedJSONWebSignatureSerializer(current_app.config['SECRET_KEY'])
    try:
        res = s.loads(token, return_header=True)
    except BadSignature:
        raise AuthFailedException(msg='非法令牌', error_code=8002)
    except SignatureExpired:
        raise AuthFailedException(msg='令牌已过期', error_code=8003)
    # 解析令牌信息
    return {
        'uid': res[0]['uid'],
        'type': res[0]['type'],
        'scope': res[0]['scope'],
        'create_at': res[1]['iat'],
        'expire_in': res[1]['exp'],
    }
